const Sequelize = require("sequelize");
const { dbConfig } = require("../config/config");
const dayjs = require("dayjs");

const { database, username, password, host, dialect } = dbConfig;

const sequelize = new Sequelize(database, username, password, { host, dialect, pool: { max: 5, min: 0, idle: 10000 } });

const logEditField = (oldRow, newRow) => {
  let str = ``;
  oldRow = oldRow.toJSON ? oldRow.toJSON() : oldRow;
  newRow = newRow ? newRow.toJSON() : newRow;

  let keyRows = Object.keys(oldRow);
  for (let i = 0; i < keyRows.length; i++) {
    let key = keyRows[i];

    if (key !== "created_date" && key !== "updated_date" && oldRow[key] !== newRow[key]) {
      let oldVal = oldRow[key];
      if (typeof oldVal === "string") {
        oldVal = oldVal.replace(/<p>/g, "").replace(/<\/p>/g, "");
      }

      let newVal = newRow[key];
      if (typeof newVal === "string") {
        newVal = newVal.replace(/<p>/g, "").replace(/<\/p>/g, "");
      }
      str += ` ${key} 从<span class="bold"> ${oldVal} </span>  变更为 <span class="bold"> ${newVal} </span>，<br>`;
    }
  }
  return str;
};

const logCreateField = (oldRow) => {
  let str = ``;
  oldRow = oldRow.toJSON ? oldRow.toJSON() : oldRow;
  let keyRows = Object.keys(oldRow);

  for (let i = 0; i < keyRows.length; i++) {
    let key = keyRows[i];

    if (key !== "created_date" && key !== "updated_date") {
      let newVal = oldRow[key];
      if (typeof newVal === "string") {
        newVal = newVal.replace(/<p>/g, "").replace(/<\/p>/g, "");
      }

      str += `<span class="bold"> ${key} </span> 为 <span class="bold"> ${newVal} </span>，<br>`;
    }
  }
  return str;
};

let model = {};
const define = (name, attributes) => {
  let attrs = {};
  for (let key in attributes) {
    let value = attributes[key];
    if (typeof value === "object" && value["type"]) {
      value.allowNull = value.allowNull || false;
      attrs[key] = value;
    } else {
      attrs[key] = {
        type: value,
        allowNull: false,
      };
    }
  }

  attrs.created_date = {
    type: Sequelize.DATE,
    allowNull: false,
    defaultValue: sequelize.literal("CURRENT_TIMESTAMP"),
    comment: "创建时间",
    get() {
      return dayjs(this.getDataValue("created_date")).format("YYYY-MM-DD HH:mm:ss");
    },
  };

  attrs.updated_date = {
    type: Sequelize.DATE,
    allowNull: false,
    comment: "更新时间",
    defaultValue: sequelize.literal("CURRENT_TIMESTAMP"),
    get() {
      return dayjs(this.getDataValue("updated_date")).format("YYYY-MM-DD HH:mm:ss");
    },
  };

  model[name] = sequelize.define(name, attrs, {
    tableName: name,
    timestamps: false,
    hooks: {
      beforeValidate: (obj) => {
        let now = Date.now();
        if (obj.isNewRecord) {
          obj.created_date = now;
          obj.updated_date = now;
        } else {
          obj.updated_date = now;
        }
      },
      afterCreate: async (obj) => {
        let tableName = obj._modelOptions.tableName;
        if (tableName !== "sys_log") {
          let logStr = logCreateField(obj);
          await model["sys_log"].create({ table_name: tableName, operate: "新增", content: logStr });
        }
      },

      afterDestroy: async (obj) => {
        let id = obj.id;
        let tableName = obj._modelOptions.tableName;
        if (tableName !== "sys_log") {
          await model["sys_log"].create({ table_name: tableName, operate: "删除", content: `用户删除id为 <span class="bold"> ${id} </span>` });
        }
      },

      beforeUpdate: async (obj) => {
        let tableName = obj._modelOptions.tableName;
        if (tableName !== "sys_log") {
          let id = obj.id;
          let tableName = obj._modelOptions.tableName;
          let updateRow = await model[tableName].findOne({ where: { id } });
          let logStr = logEditField(updateRow, obj);
          await model["sys_log"].create({ table_name: tableName, operate: "修改", content: logStr });
        }
      },
    },
  });
  return model[name];
};

module.exports = {
  sequelize,
  define,
  sync: () => {
    if (process.env.NODE_ENV !== "production") {
      sequelize.sync({ force: false });
    } else {
      throw new Error("Cannot sync() when NODE_ENV is set to 'production'.");
    }
  },
};
